-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for creating Custom Event Types with schemas validation #83
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
String eventType = getUnVersionedEventTypeFromJson(cdEventJson); | ||
CDEventConstants.CDEventTypes cdEventType = getCDEventTypeEnum(eventType); | ||
public static <T extends CDEvent> CloudEvent customCDEventAsCloudEvent(T customCDEvent, boolean validateContextSchema) { | ||
Optional.of(customCDEvent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not so sure about the use of Optional
here instead of a null and validation check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah make sense
* @return valid cdEvent | ||
*/ | ||
public static boolean validateWithContextSchemaUri(CDEvent customCDEvent) { | ||
return Optional.ofNullable(customCDEvent.customSchemaUri()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment on Optional
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rjalander Overall looks good. Most comments are fairly minor with one suggestion of how validation should return errors to be populated in the exception message (even add a CDEventsValidationException
"customDataContentType" | ||
}) | ||
@Generated("jsonschema2pojo") | ||
public class Customresourcecreated { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very odd class name. The lack of camel casing I mean? I know it's a test class, but just seems odd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah noticed, but this is generated from jsonschema2pojo
Anyway removed this class as per the latest approach.
|
||
private static CloudEvent buildCloudEvent(CDEvent cdEvent) throws URISyntaxException { | ||
String cdEventJson = cdEventAsJson(cdEvent); | ||
log.info("CDEvent with type {} as json - {}", cdEvent.currentCDEventType(), cdEventJson); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I wonder if this should be a debug log with the raw json in there. It seems overkill with it for info. How do you feel about changing this to log.debug
for the JSON and having the log.info
just having the CDEvent with type {}
String eventType = getUnVersionedEventTypeFromJson(cdEventJson); | ||
CDEventConstants.CDEventTypes cdEventType = getCDEventTypeEnum(eventType); | ||
try { | ||
CDEvent cdEvent = (CDEvent) new ObjectMapper().readValue(cdEventJson, cdEventType.getEventClass()); | ||
CDEvent cdEvent = new ObjectMapper().readValue(cdEventJson, cdEventType.getEventClass()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we constructing a new object mapper every time?
Is this method only ever called once? Even so we probably should move it to a field
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this method using the existing APIs
CDEventConstants.CDEventTypes cdEventType = getCDEventTypeEnum(eventType); | ||
public static <T extends CDEvent> CloudEvent customCDEventAsCloudEvent(T customCDEvent, boolean validateContextSchema) { | ||
if (!validateCustomCDEvent(customCDEvent, validateContextSchema)) { | ||
throw new CDEventsException("Custom CDEvent validation failed."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not say why something has failed in the exception? We should probably create an issue for that if that's the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the method with in the condition logs the reason for failures before the exception is thrown.
*/ | ||
public static <T extends CDEvent> T customCDEventFromJson(String customCDEventJson, Class<T> eventClass, boolean validateContextSchema) { | ||
try { | ||
T cdEvent = new ObjectMapper().readValue(customCDEventJson, eventClass); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comment here with the object mapper. We can just move this to a static field
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this method now and using it from existing code
public static <T extends CDEvent> T customCDEventFromJson(String customCDEventJson, Class<T> eventClass, boolean validateContextSchema) { | ||
try { | ||
T cdEvent = new ObjectMapper().readValue(customCDEventJson, eventClass); | ||
if (!validateCustomCDEvent(cdEvent, validateContextSchema)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment above with the reasons something has failed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using an existing method now, and added more logging for the failure reason
* @param customCDEvent | ||
* @return valid cdEvent | ||
*/ | ||
public static boolean validateWithOfficialCustomSchema(CDEvent customCDEvent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
void testCustomResourceEventFromJsonConformance() throws IOException { | ||
|
||
// Use spec/custom/conformance.json to test once Links are implemented for SDK | ||
//File customResourceCreatedExample = new File(CUSTOM_SPEC_FOLDER + "conformance.json"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//File customResourceCreatedExample = new File(CUSTOM_SPEC_FOLDER + "conformance.json"); | |
// File customResourceCreatedExample = new File(CUSTOM_SPEC_FOLDER + "conformance.json"); | |
cdEvent.setSubjectNestedList(Arrays.asList("val1", "val2")); | ||
|
||
cdEvent.setCustomSchemaUri(new File("src/test/resources/customresourcecreated.json").toURI()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This spacing seems really odd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @rjalander - I've not reviewed the whole code, but I have a comment about downloading the schema provided in an event, please let me know what you think about it.
On golang side, I have not added validation based on schemaUri
yet, I'm working on it. I wanted to do it as a separate PR because schemaUri
applies to all events, custom and not.
} | ||
log.info("Validate custom CDEvent against context.schemaUri - {}", customCDEvent.customSchemaUri()); | ||
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); | ||
JsonSchema jsonSchema = factory.getSchema(customCDEvent.customSchemaUri()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should not promote a model where for every message the SDK reaches out to some internet location to fetch the schema. The way I was thinking of implementing this for the sdk-go is to let user register a custom schema, so that it's loaded once and re-used from memory, and then give users an option to decide what to do if the custom schemaURI
is not in the in-memory schema cache, i.e. fail or try to download the schema, with the former as default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes agree, will do the required changes in a separate PR. Removed this implementation from current PR and created issue to work on #84
* @return custom schema URI | ||
*/ | ||
@Override | ||
public URI customSchemaUri() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: the field name is schemaUri
- perhaps the method name should match it for clarity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changing it to contextSchemaUri()
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Thank you @aalmiray @xibz @afrittoli for reviewing this PR Please review the latest changes. |
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
// Code generated by dev.cdevents.generator.CDEventsGenerator. DO NOT EDIT. | ||
|
||
/* | ||
Copyright 2023 The CDEvents Authors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2024?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it is generated from a common template for all the existing and new events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of my comments are nit, but I had one thing that I think we should change. Doesn't have to be this PR, but a follow up one maybe after some discussion about it in CDEvents
Otherwise looks good! Since none of my comments are blocking, approved!
docs/CUSTOM_CDEVENTS.md
Outdated
</dependency> | ||
``` | ||
### Create a Custom CDEvent | ||
Custom CDEvent can be created using a class `CustomTypeEvent` packaged with in `cdevents-sdk-java` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reads very similarly to the sentence above:
Custom events follow the CDEvents format and can be defined via the
CustomTypeEvent
class, available since v0.4.
How about changing the wording here to be something more like
In this example, we will create a custom event for our tool utilizing the new `CustomTypeEvent`
log.info("Processing event JsonSchema file: {}", file.getAbsolutePath()); | ||
try { | ||
JsonNode rootNode = objectMapper.readTree(file); | ||
JsonNode contextNode = rootNode.get("properties").get("context").get("properties"); | ||
JsonNode subjectNode = rootNode.get("properties").get("subject").get("properties"); | ||
String schemaURL = rootNode.get("$id").asText(); | ||
boolean isCustomEvent = schemaURL.endsWith("custom"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems really fragile. So any URL that ends with custom
is assumed to be custom
? Do we define that anywhere? Basically if we have some other even name "some/spec/that-has-custom"
would be skipped is it wasn't a custom event
While concerning, and I dont think it needs to be addressed in this PR, can you please add a comment or a TODO to make it less fragile? This may require work in the spec SIG to discuss how to easily identify custom events based on URL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, not looking for custom event schema to check isCustomEvent
here, generating a base CustomTypeEvent.java
from an official schema.json, which has "$id": "https://cdevents.dev/0.5.0-draft/schema/custom",
.
And this class file will be used to create any custom events
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this in the CDEvents WG and agreed that extending the match to schema/custom
should be sufficient. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah sounds good to me.
updateSubjectContentProperties(schemaData, subjectContentNode); | ||
schemaData.setCustomEvent(isCustomEvent); | ||
|
||
if (!isCustomEvent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: We can probably just this up some and inverse the if statement
if (isCustomEvent) {
return schemaData;
}
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
@aalmiray @afrittoli could you please review this PR and approve If there are no further comments. |
Changes to add APIs support to create
customCDEventAsCloudEvent
andcustomCDEventFromJson
also includes the validation of an official custom schema.json
Note:
Custom event support as per SDK support
Created sample
CustomResourceCDEvent.java
to test APIs as per example